function randRange(start, end) {
    var range = end - start + 1;
    return Math.floor((Math.random() * range) + start);
}

//console.log(randRange(0,1));

function shuffle(elements) {
    var length = elements.length;
    for (var i = 0; i < length - 1; i++) {
        var j = randRange(i, length - 1);
        var tmp = elements[i];
        elements[i] = elements[j];
        elements[j] = tmp;
    }
}

function choice(elements) {
    var n = randRange(0, elements.length - 1);
    return elements[n];
}

function repeateNTimes(n, fn) {
    var result = [];
    for (var i = 0; i < n; i++) {
        result.push(fn.apply(null, Array.prototype.slice.call(arguments, 2)));
    }
    return result;
}

function group(elements) {
    var result = {};
    for (var index in elements) {
        var value = elements[index];
        if (result[value] === undefined) {
            result[value] = 1;
            continue;
        }
        result[value] += 1;
    }
    return result;
}

function pdf2cdf(pdf) {
    var cdf = pdf.slice();
    for (var i = 1; i < cdf.length - 1; i++) {
        cdf[i] += cdf[i - 1];
    }
    cdf[cdf.length - 1] = 1.0;
    return cdf;
}

function discreteSampling(probs) {
    var events = [];
    var pdf = [];
    for (var key in probs) {
        events.push(key);
        pdf.push(probs[key]);   
    }
    var cdf = pdf2cdf(pdf);
    var r = Math.random();
    for (var x in cdf) {
        if (r < cdf[x]) {
            return events[x];
        }
    }
    return events[events.length - 1];
}

function getSectionsOfTableId(length, start, end){
    start = start || 100000;
    end = end || 999999;

    if(length == 0){
        return [{start: start, end: end}];
    }

    var rang = Math.floor((end - start) / length);
    var section = [];

    for(var index = 0; index < length; index++){
        var left = start + rang * index;
        var right = start + rang * (index + 1);

        section.push({start: left, end: right - 1});
    }

    return section;
};


function getIdsByServerId(serverId, length, start, end){
    if(serverId == 0 && length > 0){
        return {start: 0, end: 0}; //invalid
    }

    var section = getSectionsOfTableId(length, start, end);
    if(length == 0){
        return section[0];
    }

    return section[serverId - 1];
};

function getServerIdByTableId(tableId, length, start, end){
    var section = getSectionsOfTableId(length, start, end);
    var findIndex = 0;

    section.some(function(e, index){
       if(tableId >= e.start && tableId <= e.end){
           findIndex = index + 1;
           return true;
       }
    });

    return findIndex;
};

function findValue(arr, val){
    var findIndex = -1;
    arr.some(function(e, index){
        if(e === val){
            findIndex = index;
            return true;
        }
    });

    return findIndex;
};

function checkIsMjTableId(tableId) {
    return tableId % 4 == 0;
};

function checkIsPokerTableId(tableId) {
    return tableId % 4 == 1;
};

function getNextMjDbKey(dbKey) {
    var num = dbKey % 4;
    if(num == 0){
        return dbKey;
    }

    return dbKey + (4 - num);
};

function getNextPokerDbKey(dbKey) {
    var num = dbKey % 4;
    if(num == 1){
        return dbKey;
    }

    return dbKey + (4 + 1 - num);
};

function copyObject(src){
    var dst = {};

    for(var key in src){
        dst[key] = src[key];
    }

    return dst;
};

function getNonceStr(count) {
    count = count || 12;

    var alphabet = '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ';
    var length = alphabet.length;
    var cdkey = '';

    for (var i = 0; i < count; i++) {
        cdkey += alphabet[randRange(0, length - 1)];
    }

    return cdkey;
};

function parseObj(str) {
    var object = null;
    try{
        object = JSON.parse(str);
    }catch(e){
        object = null;
    }

    return object;
};

//console.log(getNonceStr(32));

exports.shuffle = shuffle;
exports.randRange = randRange;
exports.choice = choice;
exports.discreteSampling = discreteSampling;
exports.group = group;
exports.copyObject = copyObject;

exports.getSectionsOfTableId = getSectionsOfTableId;
exports.getIdsByServerId = getIdsByServerId;
exports.getServerIdByTableId = getServerIdByTableId;
exports.findValue = findValue;

exports.checkIsMjTableId = checkIsMjTableId;
exports.checkIsPokerTableId = checkIsPokerTableId;

exports.getNextMjDbKey = getNextMjDbKey;
exports.getNextPokerDbKey = getNextPokerDbKey;

exports.getNonceStr = getNonceStr;
exports.parseObj = parseObj;
